package cn.yunbamboos.rest.service.dispatcher;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.yunbamboos.exception.AppException;
import cn.yunbamboos.rest.service.IRestService;
import cn.yunbamboos.rest.service.IRestServiceInvoke;
import cn.yunbamboos.rest.service.IRestServiceList;
import cn.yunbamboos.rest.service.ISession;
import cn.yunbamboos.rest.service.ISessionContainer;
import cn.yunbamboos.rest.service.dto.out.BaseOutDTO;
import cn.yunbamboos.rest.service.logs.LogMetadataThreadLocal;
import cn.yunbamboos.rest.service.session.SessionBuilder;
import cn.yunbamboos.utils.WriteErrorResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;
import java.util.UUID;

@RestController
public class RestServiceDispatcher {

    private static final Logger logger = LoggerFactory.getLogger(RestServiceDispatcher.class);

    @Resource
    private ISessionContainer sessionContainer;
    @Resource
    private IRestServiceList restServiceList;
    @Resource
    private IRestServiceInvoke restServiceInvoke;

    // @RequestMapping("/rest/**")
    @RequestMapping("${yunbamboos.project-path}${yunbamboos.rest-service-path}/**")
    public Object restService(HttpServletRequest request, HttpServletResponse response) {
        String realUrl = request.getRequestURL().toString();
        request.getRequestURL();
        String url = request.getRequestURI();
        String clientIP = JakartaServletUtil.getClientIP(request);
        String browser = request.getHeader("User-Agent");
        // 生成接触ID 用于跟踪程序执行日志
        String traceId = UUID.randomUUID().toString();
        MDC.put("trace_id", traceId);
        LogMetadataThreadLocal.setTraceId(traceId);
        logger.debug("call rest service: {}", url);
        try {
            // 查找对应的服务
            Optional<IRestService> optional = restServiceList.get(url);
            if (optional.isEmpty()) {
                return WriteErrorResponseUtils.writeErrorResponse(404, "未找到对应服务" + url, response);
            }
            IRestService service = optional.get();
            // 请求方法
            String method = request.getMethod();
            // 读取请求类型
            if (!"POST".equals(method) && !"GET".equals(method)) {
                return WriteErrorResponseUtils.writeErrorResponse(405, StrUtil.format("该服务不支持{}方法", method), response);
            }
            // 创建session
            ISession session = new SessionBuilder()
                    .setRequest(request)
                    .setService(service)
                    .set("client_ip", clientIP) // 客户端IP
                    .set("browser", browser) // 浏览器类型
                    .set("real_url", realUrl)
                    .set("url", url)
                    .build();
            // 记录访问的客户端IP
            LogMetadataThreadLocal.setClientIp(clientIP);
            // 记录客户端类型
            LogMetadataThreadLocal.setBrowser(browser);
            // 记录访问真实url
            LogMetadataThreadLocal.setRealUrl(realUrl);
            // 记录服务路径
            LogMetadataThreadLocal.setServicePath(url);
            LogMetadataThreadLocal.setServiceName(service.name());
            // session放入到容器中
            sessionContainer.setSession(session);
            // 调用服务
            Object result = restServiceInvoke.invoke(service);
            if(ObjUtil.isNotNull(result)){
                if(result instanceof BaseOutDTO out){
                    response.setContentType(out.getMediaType().toString());
                    response.setCharacterEncoding(out.getCharacterEncoding());
                }
            }
            return result;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            if (e instanceof AppException exception) {
                return WriteErrorResponseUtils.writeErrorResponse(exception.getCode(), exception.getMsg(),response);
            } else {
                return WriteErrorResponseUtils.writeErrorResponse(500, e.getMessage(), response);
            }
        } finally {
            MDC.clear();
            // 清理释放资源
            sessionContainer.remove();
        }

    }

}
